package cn.edu.cuit.elena.web.service;

import java.io.IOException;
import java.io.PrintWriter;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import cn.edu.cuit.elena.trace.Tracer;
import cn.edu.cuit.elena.transaction.controller.IdentifiedRunnable;
import cn.edu.cuit.elena.transaction.query.HiveQueryExecutor;
import cn.edu.cuit.elena.transaction.query.HiveQueryExecutor.HiveIdentifiableRunnableImp;
import cn.edu.cuit.elena.transaction.system.UserContext;
import cn.edu.cuit.elena.web.System;
import cn.edu.cuit.elena.web.service.ServiceServlet.ServiceConstants;
import cn.edu.cuit.elena.web.tool.JsonHelper;

public class ScriptQueryServlet
    extends HttpServlet
{
    /**
     * Caches task result(task.getoutput())
     * */
    Map<String, String> taskCache = new HashMap<String, String>();

    /**
     * Caches console (tasks)
     * */
    Map<String, String> consoleCache = new HashMap<String, String>();

    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    /**
     * The doGet method of the servlet. <br>
     * 
     * This method is called when a form has its tag value method equals to get.
     * 
     * @param request
     *            the request send by the client to the server
     * @param response
     *            the response send by the server to the client
     * @throws ServletException
     *             if an error occurred
     * @throws IOException
     *             if an error occurred
     */
    public void doGet( HttpServletRequest request, HttpServletResponse response ) throws ServletException, IOException
    {

        doPost( request, response );
    }

    /**
     * The doPost method of the servlet. <br>
     * 
     * This method is called when a form has its tag value method equals to post.
     * 
     * @param request
     *            the request send by the client to the server
     * @param response
     *            the response send by the server to the client
     * @throws ServletException
     *             if an error occurred
     * @throws IOException
     *             if an error occurred
     */
    public void doPost( HttpServletRequest request, HttpServletResponse response ) throws ServletException, IOException
    {

        response.setContentType( "text/html" );
        PrintWriter out = response.getWriter();
        String para = request.getParameter( "kind" );
        UserContext userContext = (UserContext) request.getSession().getAttribute( ServiceConstants.USERCONTEXT.mark() );
        if( "showtables".equals( para ) )
        {
//            System.getBaseDao().execute( "use hive_remote" );
            List<Map<String, String>> list = System.getHiveRemote().queryForMap( "select * from hive_remote.TBLS" );

            List<Map<String, String>> temp = new LinkedList<Map<String, String>>();
            for( Map<String, String> map : list )
            {
                if( map.get( "TBL_NAME" ).trim().startsWith( userContext.getIdentifier() ) )
                {
                    String string = map.get( "TBL_NAME" ).trim();
                    int index_1 = map.get( "TBL_NAME" ).indexOf( "_" );
                    String userId = string.substring( 0, index_1 );
                    String tstring = string.substring( index_1 + 1 );
                    int index_2 = tstring.indexOf( "_" );
                    String schemaName = string.substring( index_1 + 1, index_1 + index_2 + 1 );
                    String tableName = string.substring( index_1 + index_2 + 2 );
                    Map<String, String> tmap = new HashMap<String, String>();
                    tmap.put( "hivetablename", string );
                    tmap.put( "tablename", tableName );
                    tmap.put( "hdfspath", "/user/quintus/" + userId + "/" + schemaName+"/"+tableName );
                    temp.add( tmap );
                }
            }

            String json = JsonHelper.getNewInstance().toJson( temp );

            Tracer.debugTrace( ScriptQueryServlet.class, "Tables json : " + json, null );
            out.write( json );
            out.flush();
            out.close();
        }
        else if( "compile".equals( para ) )
        {
            String statement = request.getParameter( "statement" ) == null ? "" : request.getParameter( "statement" );

            String[] lines = statement.split( "\n" );

            for( String line : lines )
            {
                if( line.trim().startsWith( "--" ) || line.trim().startsWith( "#" ) || line.trim().startsWith( "//" ) )
                {
                    continue;
                }

                if( !line.startsWith( "select" ) && !line.startsWith( "SELECT" ) )
                {
                    out.write( "3" );
                    out.flush();
                    out.close();
                    return;
                }

                if( !line.contains( "from" ) && !line.contains( "FROM" ) )
                {
                    out.write( "3" );
                    out.flush();
                    out.close();
                    return;
                }

                out.write( "1" );
                out.flush();
                out.close();
            }
        }
        else if( "launch".equals( para ) )
        {
            String statement = request.getParameter( "statement" );

            String[] ss = statement.split( "\n" );
            for( String s : ss )
            {
                if( s.startsWith( "--" ) || s.startsWith( "#" ) || s.startsWith( "//" ) )
                {
                    continue;
                }
                statement = s;
                break;
            }

            HiveQueryExecutor hiveQueryExecutor = System.getHiveQueryExecutor();
            //current time as id
            String taskId = String.valueOf( java.lang.System.currentTimeMillis() );
            hiveQueryExecutor.doQuery( taskId, statement );
            consoleCache.put( taskId, "" );
            taskCache.put( taskId, "" );
            out.write( "1" );
            out.flush();
            out.close();
        }
        else if( "console".equals( para ) )
        {
            Map<String, IdentifiedRunnable> tasks = System.getSystemTaskMonitor().getTasks();
            Map<String, IdentifiedRunnable> retiredTasks = System.getSystemTaskMonitor().getRetiredTasks();
            List<Map<String, String>> list = new LinkedList<Map<String, String>>();
            for( Entry<String, IdentifiedRunnable> entry : tasks.entrySet() )
            {
                String taskId = entry.getKey();
                IdentifiedRunnable task = entry.getValue();
                if( task instanceof HiveIdentifiableRunnableImp )
                {
                    Map<String, String> temp = new HashMap<String, String>();
                    temp.put( "submittime", taskId );
                    temp.put( "hql", ( (HiveIdentifiableRunnableImp) task ).getHQL() );
                    temp.put( "taskid", ( (HiveIdentifiableRunnableImp) task ).getIdentifier() );
                    temp.put( "progress", String.valueOf( task.getProgression() ) );
                    list.add( temp );
                }
            }

            for( Entry<String, IdentifiedRunnable> entry : retiredTasks.entrySet() )
            {
                String taskId = entry.getKey();
                IdentifiedRunnable task = entry.getValue();
                if( task instanceof HiveIdentifiableRunnableImp )
                {
                    Map<String, String> temp = new HashMap<String, String>();
                    temp.put( "submittime", taskId );
                    temp.put( "hql", ( (HiveIdentifiableRunnableImp) task ).getHQL() );
                    temp.put( "taskid", ( (HiveIdentifiableRunnableImp) task ).getIdentifier() );
                    temp.put( "progress", String.valueOf( task.getProgression() ) );
                    list.add( temp );
                }
            }

            String json = JsonHelper.getNewInstance().toJson( list );

            if( consoleCache.get( userContext.getIdentifier() ) == null
                || !consoleCache.get( userContext.getIdentifier() ).equals( json ) )
            {
                Tracer.debugTrace( ScriptQueryServlet.class, "console json : " + json, null );
                consoleCache.put( userContext.getIdentifier(), json );
                out.write( json );
                out.flush();
                out.close();
            }
            else
            {
                out.close();
            }
        }
        else if( "result".equals( para ) )
        {

            String taskId = request.getParameter( "taskId" );
            IdentifiedRunnable task = System.getSystemTaskMonitor().getTaskById( taskId ) == null ? System
                .getSystemTaskMonitor().getRetiredTaskById( taskId ) : System.getSystemTaskMonitor().getTaskById(
                taskId );
            if( task == null )
            {

                out.close();
                return;
            }
            ResultSet resultSet = (ResultSet) task.getResult().getInfomation();

            StringBuilder stringBuilder = new StringBuilder();

            if( resultSet != null )
            {
                try
                {
                    ResultSetMetaData metaData = resultSet.getMetaData();
                    int columnCount = metaData.getColumnCount();
                    //                    stringBuilder.append( " <BR/><table border='0.5'><tr>" );
                    for( int index = 1; index <= columnCount; index++ )
                    {
                        //                        stringBuilder.append( "<td>" );
                        stringBuilder.append( "  " );
                        stringBuilder.append( metaData.getColumnName( index ) );
                        //                        stringBuilder.append( "</td>" );
                    }
                    //                    stringBuilder.append( "</tr>" );
                    stringBuilder.append( "\n" );

                    if( taskCache.get( taskId ) != null && !taskCache.get( taskId ).equals( "" ) )
                    {
                        out.write( taskCache.get( taskId ) );
                        out.flush();
                        out.close();
                        return;
                    }
                    while( resultSet.next() )
                    {
                        //                        stringBuilder.append( "<tr>" );
                        for( int index = 1; index <= columnCount; index++ )
                        {
                            //                            stringBuilder.append( "<td>" );
                            stringBuilder.append( resultSet.getString( index ) );
                            stringBuilder.append( "       " );
                            //                            stringBuilder.append( "</td>" );
                        }
                        //                        stringBuilder.append( "</tr>" );
                        stringBuilder.append( "\n" );
                    }
                    //                    stringBuilder.append( "</table> " );

                    String outputString = new String( stringBuilder );
                    taskCache.put( taskId, outputString );
                    Tracer.debugTrace( CommonQueryServlet.class, "query result : " + outputString, null );
                    out.write( outputString );
                    out.flush();
                    out.close();

                }
                catch( Exception e )
                {
                    Tracer.debugTrace( CommonQueryServlet.class, "Result Exception : " + e.getMessage(), null );
                    out.write( "" );
                    out.flush();
                    out.close();
                }
            }
        }
        else if( "refresh".equals( para ) )
        {
            consoleCache.put( userContext.getIdentifier(), "" );
        }
    }
}
